package com.pb.wkflow.core.service.impl;

import com.pb.wkflow.core.config.DeleteReasonConstants;
import com.pb.wkflow.core.entity.ActHiCommentEntity;
import com.pb.wkflow.core.entity.ActHiTaskEntity;
import com.pb.wkflow.core.mapper.ActHiCommentMapper;
import com.pb.wkflow.core.mapper.ActHiTaskMapper;
import com.pb.wkflow.core.service.WorkflowInstanceService;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.runtime.ActivityInstance;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 苗益辉
 * @date 2022/9/23 10:40
 */
@Service
public class WorkflowInstanceServiceImpl implements WorkflowInstanceService {

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    HistoryService historyService;

    @Autowired
    ActHiCommentMapper actHiCommentMapper;

    @Autowired
    ActHiTaskMapper actHiTaskMapper;

    @Override
    public ProcessInstance findByProcessInstanceId(String processInstanceId) {
        return runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
    }

    @Override
    public void setVariables(String processInstanceId, Map<String, Object> variables) {
        runtimeService.setVariables(processInstanceId, variables);
    }

    @Override
    public void deleteProcessInstance(List<String> processInstanceIds) {
        runtimeService.deleteProcessInstancesIfExists(
                processInstanceIds,
                DeleteReasonConstants.DELETE,
                true,
                false,
                true
        );
    }

    @Override
    public void deleteHistoryProcessInstance(List<String> processInstances) {
        historyService.deleteHistoricProcessInstancesIfExists(processInstances);
    }

    @Override
    public List<HistoricTaskInstance> queryHistoryTaskInstance(String processInstanceId) {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();
    }

    @Override
    public List<HistoricTaskInstance> queryFirstHistoryTaskInstance(String processInstanceId) {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .listPage(0,1);
    }

    @Override
    public List<HistoricActivityInstance> queryHistoryServiceActivityInstance(String processInstanceId) {
        return historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();
    }

    @Override
    public List<HistoricActivityInstance> queryHistoryServiceActivityInstanceAfter(String processInstanceId, Date startTime) {
        return historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .startedAfter(startTime)
                .list();
    }

    @Override
    public Long countHistoryServiceActivityInstance(String processInstanceId) {
        return historyService.createHistoricActivityInstanceQuery()
                .activityType("serviceTask")
                .processInstanceId(processInstanceId)
                .count();
    }

    @Override
    public List<HistoricVariableInstance> queryHistoryVariableInstance(String processInstanceId) {
        return historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
    }

    @Override
    public HistoricProcessInstance queryHistoryProcessInstance(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
    }

    @Override
    public List<HistoricTaskInstance> queryFinishTaskInstance(String processInstanceId) {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list();
    }

    @Override
    public List<HistoricProcessInstance> querySubHistoryProcessInstance(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery()
                .superProcessInstanceId(processInstanceId)
                .list();
    }

    @Override
    public Map<String, List<ActHiCommentEntity>> findCommentsByProcessInstanceId(String processInstanceId) {
        List<ActHiCommentEntity> commentEntities = actHiCommentMapper.findCommentsByProcessInstanceId(processInstanceId);
        if (commentEntities != null && !commentEntities.isEmpty()) {
            return commentEntities.stream().collect(
                    Collectors.groupingBy(ActHiCommentEntity::getTaskId)
            );
        } else {
            return new HashMap<>(1);
        }
    }

    @Override
    public ActivityInstance findActivityInstance(String processInstanceId) {
        return runtimeService.getActivityInstance(processInstanceId);
    }

    @Override
    public List<ActHiTaskEntity> findTaskListByProcessInstanceId(String processInstanceId) {
        return actHiTaskMapper.findListByProcessInstanceId(processInstanceId);
    }

    @Override
    public int isActiveProcInstance(String procDefineKey) {
        return runtimeService.createProcessInstanceQuery().processDefinitionKey(procDefineKey)
                .listPage(0, 1).size();
    }
}
